import datetime
import re
from google.appengine.ext import db

import sys
sys.path.insert(0, 'packages')
from wtforms.ext.appengine.db import model_form
from wtforms.fields import BooleanField, HiddenField, Field
from wtforms.widgets import TextInput

__all__ = [
    'UserInfo',
    'Account',
    'Transaction',
    'AccountForm',
    'TransactionForm',
    ]

def period(last_month=False, from_date=None, to_date=None):
    today = datetime.date.today()
    if not to_date or today < to_date: to_date = today
    if last_month:
        past = today - datetime.timedelta(days=30)
        if not from_date or past > from_date: from_date = past
    return (from_date, to_date)
    

class Account(db.Model):
    name = db.StringProperty(required=True)
    currency = db.StringProperty(choices=set(['BGN', 'CHF', 'EUR']))
    initial = db.FloatProperty(default=0.)
    opened = db.DateProperty()
    
    def __str__(self):
        return self.currency + '.' + self.name
    
    def transactions(self, period=(None, None), sign=0, internal=True):
        l = []
        for trns,attr in [(self.external_trns, 'amount'), (self.internal_trns, 'to_amount')]:
            if period[0]: trns.filter('date >= ', period[0])
            if period[1]: trns.filter('date <=', period[1])
            if not internal: trns.filter('to_account == ', None)
            l.extend([getattr(t, attr) for t in trns])
        return [t for t in l if sign*t >= 0]
            
    def balance(self, last_month=False):
        p = period(last_month)
        b = sum(self.transactions(p))
        if not last_month:
            b += self.initial
        return b 
        
    def daily_spending(self, last_month=False):
        p = period(last_month, self.opened)
        trns = self.transactions(p, sign=-1, internal=False)
        if not p[0] or not p[1] or p[0] == p[1]: return 0.
        return sum([t for t in trns]) / (p[1] - p[0]).days
        

class Transaction(db.Model):
    created = db.DateTimeProperty(auto_now_add=True)
    date = db.DateProperty(required=True)
    amount = db.FloatProperty(required=True)
    account = db.ReferenceProperty(Account, collection_name='external_trns', required=True)
    tags = db.StringListProperty()
    to_amount = db.FloatProperty(default=0.)
    to_account = db.ReferenceProperty(Account, collection_name='internal_trns')
    
    def internal(self):
        return self.to_account is not None
    
    def __str__(self):
        return '%s,%.2f,%s,%.2f,%s'%(self.date, self.amount, self.account.name, self.to_amount, self.to_account)

class UserInfo(db.Model):
    user = db.UserProperty()
    last_trn_date = db.DateProperty()
    last_trn_account = db.ReferenceProperty(Account)

class TagListField(Field):
    widget = TextInput()

    def _value(self):
        return u' '.join(self.data) if self.data else u''

    def process_formdata(self, valuelist):
        self.data = re.findall(r'[-\.\w]+', valuelist[0]) if valuelist else []
            
AccountForm = model_form(Account)
AccountForm.id = HiddenField()

TransactionForm = model_form(Transaction, exclude=['tags'])
TransactionForm.income = BooleanField()
TransactionForm.tags = TagListField()
TransactionForm.id = HiddenField()